package com.bigknow.appstore.web.app.service.impl;

import com.bigknow.appstore.web.app.service.IAppStoreService;
import com.bigknow.appstore.web.app.vo.AppCategoryVO;
import com.bigknow.appstore.web.app.vo.AppVO;
import com.bigknow.appstore.web.app.vo.BannerVO;
import com.bigknow.appstore.web.base.service.IFusionService;
import com.bigknow.appstore.web.console.app.*;
import com.bigknow.fusion.common.inf.server.appstore.FusionHandler;
import com.bigknow.fusion.common.model.appstore.DataNodeStatus;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.tools.ant.util.DateUtils;
import org.bson.types.ObjectId;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by zhangwei on 2016/10/14.
 */
@Service
public class AppStoreService implements IAppStoreService {

    @Autowired
    private Datastore ds;

    @Autowired
    private IFusionService fusionService;

    @Override
    public Map<Integer, List<AppCategoryVO>> getCategories() {
        Map<Integer, List<AppCategoryVO>> map = new HashMap<Integer, List<AppCategoryVO>>();
        List<ApplicationCategory> categories = ds.find(ApplicationCategory.class).asList();
        List<AppCategoryVO> _categories = new ArrayList<AppCategoryVO>();
        int count = 0;
        int index = 0;
        categories.sort(Comparator.comparingInt(c -> c.getSort()));
        for (ApplicationCategory category : categories) {
            AppCategoryVO vo = new AppCategoryVO();
            vo.setId(category.getId());
            vo.setName(category.getName());
            _categories.add(vo);
            if (count > 0) {
                map.put(index, new ArrayList<>(_categories));
                _categories = new ArrayList<AppCategoryVO>();
                index++;
                count = 0;
                continue;
            }
            count++;
        }
        if (_categories.size() > 0) {
            map.put(index, new ArrayList<>(_categories));
        }
        return map;
    }

    @Override
    public List<AppVO> top(int number) {
        List<Application> apps = ds.find(Application.class).filter("state", ApplicationState.PUBLISHED).limit(number).order("-subscribeCount").asList();
        List<AppVO> topApps = new ArrayList<AppVO>();
        for (Application app : apps) {
            AppVO vo = new AppVO();
            vo.setId(app.getId());
            vo.setName(app.getName());
            vo.setPic(app.getLogoFile());
            vo.setStar(app.getStar());
            vo.setSubscribeCount(app.getSubscribeCount());
            topApps.add(vo);
        }
        return topApps;
    }

    @Override
    public List<AppVO> getCommonApps() {
        List<CommonApplication> commonApps = ds.find(CommonApplication.class).asList();
        List<AppVO> appVOs = new ArrayList<AppVO>();
        for (CommonApplication commonApp : commonApps) {
            List<String> appIds = commonApp.getApplications();
            for (String id : appIds) {
                Application app = ds.find(Application.class).filter("id", id).filter("state", ApplicationState.PUBLISHED).get();
                if (app != null) {
                    AppVO vo = new AppVO();
                    vo.setId(app.getId());
                    vo.setName(app.getName());
                    vo.setCategory(ds.find(ApplicationCategory.class).filter("id", app.getCategoryId()).get().getName());
                    vo.setDesc(app.getDescription());
                    vo.setPic(app.getLogoFile());
                    vo.setPublishTime(DateUtils.format(app.getPublishedTime(), com.bigknow.appstore.auth.infrastructure.DateUtils.DATE_FORMAT));
                    vo.setStar(app.getStar());
                    vo.setSubscribeCount(app.getSubscribeCount());
                    appVOs.add(vo);
                }
            }
        }
        return appVOs;
    }

    @Override
    public List<AppVO> getRecommendApps() {
        List<RecommendApplication> recommendApps = ds.find(RecommendApplication.class).asList();
        List<AppVO> appVOs = new ArrayList<AppVO>();
        for (RecommendApplication recommendApp : recommendApps) {
            List<String> appIds = recommendApp.getApplications();
            for (String id : appIds) {
                Application app = ds.find(Application.class).filter("id", id).filter("state", ApplicationState.PUBLISHED).get();
                if (app != null) {
                    AppVO vo = new AppVO();
                    vo.setId(app.getId());
                    vo.setName(app.getName());
                    vo.setCategory(ds.find(ApplicationCategory.class).filter("id", app.getCategoryId()).get().getName());
                    vo.setPic(app.getLogoFile());
                    vo.setSubscribeCount(app.getSubscribeCount());
                    appVOs.add(vo);
                }
            }
        }
        return appVOs;
    }

    @Override
    public List<BannerVO> getBanners() {
        List<BannerVO> bannerVOs = new ArrayList<BannerVO>();
        List<RecommendBanner> banners = ds.find(RecommendBanner.class).asList();
        for (RecommendBanner banner : banners) {
            BannerVO bannerVO = new BannerVO();
            bannerVO.setPic(banner.getImgFile());
            bannerVO.setId(banner.getId());
            bannerVO.setName(banner.getName());
            bannerVOs.add(bannerVO);
        }
        return bannerVOs;
    }

    @Override
    public AppVO getApp(String id) {
        AppVO appVO = new AppVO();
        com.bigknow.appstore.web.base.entity.User user = (com.bigknow.appstore.web.base.entity.User) SecurityUtils.getSubject().getPrincipal();
        Application app = ds.find(Application.class).filter("id", id).get();
        appVO.setId(app.getId());
        appVO.setName(app.getName());
        appVO.setSubscribeCount(app.getSubscribeCount());
        appVO.setPic(app.getLogoFile());
        appVO.setStar(app.getStar());
        appVO.setPublishTime(DateUtils.format(app.getPublishedTime(), com.bigknow.appstore.auth.infrastructure.DateUtils.DATE_FORMAT));
        ApplicationCategory category = ds.find(ApplicationCategory.class).filter("id", app.getCategoryId()).get();
        if (category != null){
            appVO.setCategory(category.getName());
        }
        appVO.setCategoryId(app.getCategoryId());
        appVO.setDesc(app.getDescription());
        appVO.setVersionFeature(app.getVersionFeature());
        appVO.setScreenshots(app.getScreenshotFiles());
        appVO.setUrl(app.getIndexUrl());
        appVO.setTags(getTags(app.getTags()));
        appVO.setSubscribeState(getSubscribeState(app, user));
        appVO.setDataNodeStatuses(getDataNodeStatus(app.getServiceIds(), app.getUserId()));
        if (user != null) {
            appVO.setFavorite(ds.find(Favorite.class).filter("appId", app.getId()).filter("userId", user.getId()).get() != null);
        } else {
            appVO.setFavorite(false);
        }
        //TODO 业务拥有着指定
        appVO.setBizOwner("张三");
        return appVO;
    }

    private List<DataNodeStatus> getDataNodeStatus(List<String> serviceIds, String userId) {
        if (serviceIds == null || serviceIds.size() == 0) {
            return new ArrayList<DataNodeStatus>();
        }
        FusionHandler handler = fusionService.getFusionHandler();
        return handler.getDataNodeStatus(serviceIds, userId);
    }

    private SubscribeState getSubscribeState(Application app, com.bigknow.appstore.web.base.entity.User user) {
        if (user == null) {
            return SubscribeState.FAILED;
        }

        Subscriber sub = ds.find(Subscriber.class).filter("state", SubscribeState.SUCCESS).filter("application", app).filter("user", user).get();
        if (sub == null) {
            Subscriber _sub = ds.find(Subscriber.class).filter("state", SubscribeState.APPLYING).filter("application", app).filter("user", user).get();
            if (_sub == null) {
                return SubscribeState.FAILED;
            } else {
                return SubscribeState.APPLYING;
            }
        } else {
            return SubscribeState.SUCCESS;
        }
    }

    private List<String> getTags(List<String> ids) {
        List<String> tags = new ArrayList<String>();
        if (ids.size() > 0) {
            List<Tag> _tags = ds.find(Tag.class).filter("id in", ids).asList();
            for (Tag tag : _tags) {
                tags.add(tag.getName());
            }
        }
        return tags;
    }

    public String getTagId(String name) {
        return ds.find(Tag.class).filter("name", name).get().getId();
    }

    @Override
    public List<AppVO> getRelatedApps(String id) {
        List<AppVO> appVOs = new ArrayList<AppVO>();
        Application _app = ds.find(Application.class).filter("id", id).get();
        List<Application> apps = ds.find(Application.class).filter("categoryId", _app.getCategoryId()).filter("state", ApplicationState.PUBLISHED).asList();
        List<AppVO> firstPart = new ArrayList<AppVO>();
        List<AppVO> secondPart = new ArrayList<AppVO>();
        for (Application app : apps) {
            if (StringUtils.equals(id, app.getId())) {
                continue;
            }
            AppVO appVO = new AppVO();
            appVO.setId(app.getId());
            appVO.setPic(app.getLogoFile());
            appVO.setName(app.getName());
            ApplicationCategory applicationCategory = ds.find(ApplicationCategory.class).filter("id", app.getCategoryId()).get();
            if (applicationCategory != null){
                appVO.setCategory(applicationCategory.getName());
            }
            appVO.setSubscribeCount(app.getSubscribeCount());
            if (StringUtils.equals(app.getUserId(), _app.getUserId())) {
                firstPart.add(appVO);
            } else {
                secondPart.add(appVO);
            }
        }
        appVOs.addAll(firstPart);
        appVOs.addAll(secondPart);
        return appVOs;
    }

    @Override
    public boolean isLogin() {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            return true;
        }
        return false;
    }


    @Override
    public String getUser() {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            com.bigknow.appstore.web.base.entity.User user = (com.bigknow.appstore.web.base.entity.User) SecurityUtils.getSubject().getPrincipal();
            if (user != null) {
                return user.getName();
            }
        }
        return "";
    }

    @Override
    public AppCategoryVO getCategory(String id) {
        AppCategoryVO vo = new AppCategoryVO();
        if (StringUtils.isEmpty(id)) {
            return vo;
        }
        ApplicationCategory category = ds.find(ApplicationCategory.class).filter("id", id).get();
        if (category != null) {
            vo.setId(category.getId());
            vo.setName(category.getName());
        }
        return vo;
    }


    @Override
    public List<AppVO> getAppsByCondition(String[] tagIds, String orderType, String categoryId, String appName) {
        AppSortType type = AppSortType.valueOf(orderType);
        List<Application> apps = new ArrayList<Application>();
        Query query = ds.find(Application.class);
        if (!StringUtils.isEmpty(appName)) {
            query.field("name").contains(appName);
        }
        if (!StringUtils.isEmpty(categoryId)) {
            query.filter("categoryId", categoryId);
        }
        if (type == AppSortType.HOT) {
            apps = query.filter("state", ApplicationState.PUBLISHED).order("-subscribeCount").asList();
        } else if (type == AppSortType.NEW) {
            apps = query.filter("state", ApplicationState.PUBLISHED).order("-publishedTime").asList();
        } else {
            apps = query.filter("state", ApplicationState.PUBLISHED).order("-star").asList();
        }
        List<AppVO> appVOs = new ArrayList<AppVO>();
        List<Application> results = filterApps(apps, tagIds);
        for (Application app : results) {
            AppVO vo = new AppVO();
            vo.setId(app.getId());
            vo.setName(app.getName());
            vo.setCategory(ds.find(ApplicationCategory.class).filter("id", app.getCategoryId()).get().getName());
            vo.setDesc(app.getDescription());
            vo.setPic(app.getLogoFile());
            vo.setPublishTime(DateUtils.format(app.getPublishedTime(), com.bigknow.appstore.auth.infrastructure.DateUtils.DATE_FORMAT));
            vo.setStar(app.getStar());
            vo.setSubscribeCount(app.getSubscribeCount());
            appVOs.add(vo);
        }
        return appVOs;
    }

    private List<Application> filterApps(List<Application> apps, String[] tagIds) {
        if (tagIds != null && tagIds.length > 0) {
            List<Application> results = new ArrayList<Application>();
            for (Application app : apps) {
                for (String tagId : tagIds) {
                    if (app.getTags().contains(tagId)) {
                        results.add(app);
                        break;
                    }
                }
            }
            return results;
        } else {
            return apps;
        }
    }

    @Override
    public List<Tag> getAllTags() {
        return ds.find(Tag.class).asList();
    }

    @Override
    public List<String> getBannerAppIds(String id) {
        RecommendBanner banner = ds.find(RecommendBanner.class).filter("id", id).get();
        if (banner != null) {
            return banner.getApplications();
        }
        return new ArrayList<String>();
    }

    @Override
    public List<AppVO> getAppsByIds(List<String> ids) {
        List<Application> apps = ds.find(Application.class).filter("id in", ids).filter("state", ApplicationState.PUBLISHED).asList();
        List<AppVO> appVOs = new ArrayList<AppVO>();
        for (Application app : apps) {
            AppVO vo = new AppVO();
            vo.setId(app.getId());
            vo.setName(app.getName());
            vo.setCategory(ds.find(ApplicationCategory.class).filter("id", app.getCategoryId()).get().getName());
            vo.setDesc(app.getDescription());
            vo.setPic(app.getLogoFile());
            vo.setPublishTime(DateUtils.format(app.getPublishedTime(), com.bigknow.appstore.auth.infrastructure.DateUtils.DATE_FORMAT));
            vo.setStar(app.getStar());
            vo.setSubscribeCount(app.getSubscribeCount());
            appVOs.add(vo);
        }
        return appVOs;
    }

    @Override
    public List<Tag> getTags() {
        return ds.find(Tag.class).asList();
    }

}
